/*******************************************************************************
 *
 * Copyright (c) 2000-2003 Intel Corporation
 * All rights reserved.
 * Copyright (c) 2012 France Telecom All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * - Neither name of Intel Corporation nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************/

/*!
 * \file
 */

#include "autoconfig.h"

#include "ixmlparser.h"

#include "ixmldebug.h"

#include <assert.h>
#include <stddef.h> /* for ptrdiff_t */
#include <stdio.h>
#include <stdlib.h> /* for free(), malloc() */
#include <string.h>

#ifdef _WIN32
#define strncasecmp strnicmp
#endif /* _WIN32 */

static char g_error_char = '\0';
#ifdef IXML_HAVE_SCRIPTSUPPORT
static IXML_BeforeFreeNode_t Before_Free_callback;
#endif

static const char LESSTHAN = '<';
static const char GREATERTHAN = '>';
static const char SLASH = '/';
static const char EQUALS = '=';
static const char QUOTE = '\"';
static const char SINGLEQUOTE = '\'';

static const char *WHITESPACE = "\n\t\r ";
static const char *COMPLETETAG = "/>";
static const char *ENDTAG = "</";
static const char *XMLDECL = "<?xml ";
static const char *XMLDECL2 = "<?xml?";
static const char *BEGIN_COMMENT = "<!--";
static const char *END_COMMENT = "-->";
static const char *BEGIN_PI = "<?";
static const char *END_PI = "?>";
static const char *BEGIN_DOCTYPE = "<!DOCTYPE";
static const char *CDSTART = "<![CDATA[";
static const char *CDEND = "]]>";
static const char *DEC_NUMBERS = "0123456789";
static const char *HEX_NUMBERS = "0123456789ABCDEFabcdef";

typedef struct char_info
{
        unsigned short l;
        unsigned short h;
} char_info_t;

typedef char utf8char[8];

/*!
 * \brief The letter table contains all characters in XML 1.0 plus ":", "_" and
 * ideographic.
 *
 * This table contains all the characters that an element name can start with.
 * See XML 1.0 (2nd Edition) for more details.
 */
static char_info_t Letter[] = {{0x003A, 0x003A}, /* character ":" */
        {0x0041, 0x005A},
        {0x005F, 0x005F}, /* character "_" */
        {0x0061, 0x007A},
        {0x00C0, 0x00D6},
        {0x00D8, 0x00F6},
        {0x00F8, 0x00FF},
        {0x0100, 0x0131},
        {0x0134, 0x013E},
        {0x0141, 0x0148},
        {0x014A, 0x017E},
        {0x0180, 0x01C3},
        {0x01CD, 0x01F0},
        {0x01F4, 0x01F5},
        {0x01FA, 0x0217},
        {0x0250, 0x02A8},
        {0x02BB, 0x02C1},
        {0x0386, 0x0386},
        {0x0388, 0x038A},
        {0x038C, 0x038C},
        {0x038E, 0x03A1},
        {0x03A3, 0x03CE},
        {0x03D0, 0x03D6},
        {0x03DA, 0x03DA},
        {0x03DC, 0x03DC},
        {0x03DE, 0x03DE},
        {0x03E0, 0x03E0},
        {0x03E2, 0x03F3},
        {0x0401, 0x040C},
        {0x040E, 0x044F},
        {0x0451, 0x045C},
        {0x045E, 0x0481},
        {0x0490, 0x04C4},
        {0x04C7, 0x04C8},
        {0x04CB, 0x04CC},
        {0x04D0, 0x04EB},
        {0x04EE, 0x04F5},
        {0x04F8, 0x04F9},
        {0x0531, 0x0556},
        {0x0559, 0x0559},
        {0x0561, 0x0586},
        {0x05D0, 0x05EA},
        {0x05F0, 0x05F2},
        {0x0621, 0x063A},
        {0x0641, 0x064A},
        {0x0671, 0x06B7},
        {0x06BA, 0x06BE},
        {0x06C0, 0x06CE},
        {0x06D0, 0x06D3},
        {0x06D5, 0x06D5},
        {0x06E5, 0x06E6},
        {0x0905, 0x0939},
        {0x093D, 0x093D},
        {0x0958, 0x0961},
        {0x0985, 0x098C},
        {0x098F, 0x0990},
        {0x0993, 0x09A8},
        {0x09AA, 0x09B0},
        {0x09B2, 0x09B2},
        {0x09B6, 0x09B9},
        {0x09DC, 0x09DD},
        {0x09DF, 0x09E1},
        {0x09F0, 0x09F1},
        {0x0A05, 0x0A0A},
        {0x0A0F, 0x0A10},
        {0x0A13, 0x0A28},
        {0x0A2A, 0x0A30},
        {0x0A32, 0x0A33},
        {0x0A35, 0x0A36},
        {0x0A38, 0x0A39},
        {0x0A59, 0x0A5C},
        {0x0A5E, 0x0A5E},
        {0x0A72, 0x0A74},
        {0x0A85, 0x0A8B},
        {0x0A8D, 0x0A8D},
        {0x0A8F, 0x0A91},
        {0x0A93, 0x0AA8},
        {0x0AAA, 0x0AB0},
        {0x0AB2, 0x0AB3},
        {0x0AB5, 0x0AB9},
        {0x0ABD, 0x0ABD},
        {0x0AE0, 0x0AE0},
        {0x0B05, 0x0B0C},
        {0x0B0F, 0x0B10},
        {0x0B13, 0x0B28},
        {0x0B2A, 0x0B30},
        {0x0B32, 0x0B33},
        {0x0B36, 0x0B39},
        {0x0B3D, 0x0B3D},
        {0x0B5C, 0x0B5D},
        {0x0B5F, 0x0B61},
        {0x0B85, 0x0B8A},
        {0x0B8E, 0x0B90},
        {0x0B92, 0x0B95},
        {0x0B99, 0x0B9A},
        {0x0B9C, 0x0B9C},
        {0x0B9E, 0x0B9F},
        {0x0BA3, 0x0BA4},
        {0x0BA8, 0x0BAA},
        {0x0BAE, 0x0BB5},
        {0x0BB7, 0x0BB9},
        {0x0C05, 0x0C0C},
        {0x0C0E, 0x0C10},
        {0x0C12, 0x0C28},
        {0x0C2A, 0x0C33},
        {0x0C35, 0x0C39},
        {0x0C60, 0x0C61},
        {0x0C85, 0x0C8C},
        {0x0C8E, 0x0C90},
        {0x0C92, 0x0CA8},
        {0x0CAA, 0x0CB3},
        {0x0CB5, 0x0CB9},
        {0x0CDE, 0x0CDE},
        {0x0CE0, 0x0CE1},
        {0x0D05, 0x0D0C},
        {0x0D0E, 0x0D10},
        {0x0D12, 0x0D28},
        {0x0D2A, 0x0D39},
        {0x0D60, 0x0D61},
        {0x0E01, 0x0E2E},
        {0x0E30, 0x0E30},
        {0x0E32, 0x0E33},
        {0x0E40, 0x0E45},
        {0x0E81, 0x0E82},
        {0x0E84, 0x0E84},
        {0x0E87, 0x0E88},
        {0x0E8A, 0x0E8A},
        {0x0E8D, 0x0E8D},
        {0x0E94, 0x0E97},
        {0x0E99, 0x0E9F},
        {0x0EA1, 0x0EA3},
        {0x0EA5, 0x0EA5},
        {0x0EA7, 0x0EA7},
        {0x0EAA, 0x0EAB},
        {0x0EAD, 0x0EAE},
        {0x0EB0, 0x0EB0},
        {0x0EB2, 0x0EB3},
        {0x0EBD, 0x0EBD},
        {0x0EC0, 0x0EC4},
        {0x0F40, 0x0F47},
        {0x0F49, 0x0F69},
        {0x10A0, 0x10C5},
        {0x10D0, 0x10F6},
        {0x1100, 0x1100},
        {0x1102, 0x1103},
        {0x1105, 0x1107},
        {0x1109, 0x1109},
        {0x110B, 0x110C},
        {0x110E, 0x1112},
        {0x113C, 0x113C},
        {0x113E, 0x113E},
        {0x1140, 0x1140},
        {0x114C, 0x114C},
        {0x114E, 0x114E},
        {0x1150, 0x1150},
        {0x1154, 0x1155},
        {0x1159, 0x1159},
        {0x115F, 0x1161},
        {0x1163, 0x1163},
        {0x1165, 0x1165},
        {0x1167, 0x1167},
        {0x1169, 0x1169},
        {0x116D, 0x116E},
        {0x1172, 0x1173},
        {0x1175, 0x1175},
        {0x119E, 0x119E},
        {0x11A8, 0x11A8},
        {0x11AB, 0x11AB},
        {0x11AE, 0x11AF},
        {0x11B7, 0x11B8},
        {0x11BA, 0x11BA},
        {0x11BC, 0x11C2},
        {0x11EB, 0x11EB},
        {0x11F0, 0x11F0},
        {0x11F9, 0x11F9},
        {0x1E00, 0x1E9B},
        {0x1EA0, 0x1EF9},
        {0x1F00, 0x1F15},
        {0x1F18, 0x1F1D},
        {0x1F20, 0x1F45},
        {0x1F48, 0x1F4D},
        {0x1F50, 0x1F57},
        {0x1F59, 0x1F59},
        {0x1F5B, 0x1F5B},
        {0x1F5D, 0x1F5D},
        {0x1F5F, 0x1F7D},
        {0x1F80, 0x1FB4},
        {0x1FB6, 0x1FBC},
        {0x1FBE, 0x1FBE},
        {0x1FC2, 0x1FC4},
        {0x1FC6, 0x1FCC},
        {0x1FD0, 0x1FD3},
        {0x1FD6, 0x1FDB},
        {0x1FE0, 0x1FEC},
        {0x1FF2, 0x1FF4},
        {0x1FF6, 0x1FFC},
        {0x2126, 0x2126},
        {0x212A, 0x212B},
        {0x212E, 0x212E},
        {0x2180, 0x2182},
        {0x3007, 0x3007},
        {0x3021, 0x3029}, /* these two are ideographic */
        {0x3041, 0x3094},
        {0x30A1, 0x30FA},
        {0x3105, 0x312C},
        {0x4E00, 0x9FA5}, /* ideographic */
        {0xAC00, 0xD7A3}};

/*!
 * \brief The size of the letter table array.
 */
#define LETTERTABLESIZE (sizeof(Letter) / sizeof(Letter[0]))

/*!
 * \brief The NameChar table contains CombiningChar, Extender, Digit,
 * '-', '.', less '_', ':'
 *
 * NameChar ::= Digit | '-' | '.' | CombiningChar | Extender
 * See XML 1.0 2nd Edition
 */
static char_info_t NameChar[] = {
        {0x002D, 0x002D}, /* character "-" */
        {0x002E, 0x002E}, /* character "." */
        {0x0030, 0x0039}, /* digit */
        {0x00B7, 0x00B7},
        {0x02D0, 0x02D0},
        {0x02D1, 0x02D1}, /* extended */
        {0x0300, 0x0345},
        {0x0360, 0x0361},
        {0x0387, 0x0387}, /* extended */
        {0x0483, 0x0486},
        {0x0591, 0x05A1},
        {0x05A3, 0x05B9},
        {0x05BB, 0x05BD},
        {0x05BF, 0x05BF},
        {0x05C1, 0x05C2},
        {0x05C4, 0x05C4},
        {0x0640, 0x0640}, /* extended */
        {0x064B, 0x0652},
        {0x0660, 0x0669}, /* digit */
        {0x0670, 0x0670},
        {0x06D6, 0x06DC},
        {0x06DD, 0x06DF},
        {0x06E0, 0x06E4},
        {0x06E7, 0x06E8},
        {0x06EA, 0x06ED},
        {0x06F0, 0x06F9}, /* digit */
        {0x0901, 0x0903},
        {0x093C, 0x093C},
        {0x093E, 0x094C},
        {0x094D, 0x094D},
        {0x0951, 0x0954},
        {0x0962, 0x0963},
        {0x0966, 0x096F}, /* digit */
        {0x0981, 0x0983},
        {0x09BC, 0x09BC},
        {0x09BE, 0x09BE},
        {0x09BF, 0x09BF},
        {0x09C0, 0x09C4},
        {0x09C7, 0x09C8},
        {0x09CB, 0x09CD},
        {0x09D7, 0x09D7},
        {0x09E2, 0x09E3},
        {0x09E6, 0x09EF}, /* digit */
        {0x0A02, 0x0A02},
        {0x0A3C, 0x0A3C},
        {0x0A3E, 0x0A3E},
        {0x0A3F, 0x0A3F},
        {0x0A40, 0x0A42},
        {0x0A47, 0x0A48},
        {0x0A4B, 0x0A4D},
        {0x0A66, 0x0A6F}, /* digit */
        {0x0A70, 0x0A71},
        {0x0A81, 0x0A83},
        {0x0ABC, 0x0ABC},
        {0x0ABE, 0x0AC5},
        {0x0AC7, 0x0AC9},
        {0x0ACB, 0x0ACD},
        {0x0AE6, 0x0AEF}, /* digit */
        {0x0B01, 0x0B03},
        {0x0B3C, 0x0B3C},
        {0x0B3E, 0x0B43},
        {0x0B47, 0x0B48},
        {0x0B4B, 0x0B4D},
        {0x0B56, 0x0B57},
        {0x0B66, 0x0B6F}, /* digit */
        {0x0B82, 0x0B83},
        {0x0BBE, 0x0BC2},
        {0x0BC6, 0x0BC8},
        {0x0BCA, 0x0BCD},
        {0x0BD7, 0x0BD7},
        {0x0BE7, 0x0BEF}, /* digit */
        {0x0C01, 0x0C03},
        {0x0C3E, 0x0C44},
        {0x0C46, 0x0C48},
        {0x0C4A, 0x0C4D},
        {0x0C55, 0x0C56},
        {0x0C66, 0x0C6F}, /* digit */
        {0x0C82, 0x0C83},
        {0x0CBE, 0x0CC4},
        {0x0CC6, 0x0CC8},
        {0x0CCA, 0x0CCD},
        {0x0CD5, 0x0CD6},
        {0x0CE6, 0x0CEF}, /* digit */
        {0x0D02, 0x0D03},
        {0x0D3E, 0x0D43},
        {0x0D46, 0x0D48},
        {0x0D4A, 0x0D4D},
        {0x0D57, 0x0D57},
        {0x0D66, 0x0D6F}, /* digit */
        {0x0E31, 0x0E31},
        {0x0E34, 0x0E3A},
        {0x0E46, 0x0E46}, /* extended */
        {0x0E47, 0x0E4E},
        {0x0E50, 0x0E59}, /* digit */
        {0x0EB1, 0x0EB1},
        {0x0EB4, 0x0EB9},
        {0x0EBB, 0x0EBC},
        {0x0EC6, 0x0EC6}, /* extended */
        {0x0EC8, 0x0ECD},
        {0x0ED0, 0x0ED9}, /* digit */
        {0x0F18, 0x0F19},
        {0x0F20, 0x0F29}, /* digit */
        {0x0F35, 0x0F35},
        {0x0F37, 0x0F37},
        {0x0F39, 0x0F39},
        {0x0F3E, 0x0F3E},
        {0x0F3F, 0x0F3F},
        {0x0F71, 0x0F84},
        {0x0F86, 0x0F8B},
        {0x0F90, 0x0F95},
        {0x0F97, 0x0F97},
        {0x0F99, 0x0FAD},
        {0x0FB1, 0x0FB7},
        {0x0FB9, 0x0FB9},
        {0x20D0, 0x20DC},
        {0x20E1, 0x20E1},
        {0x3005, 0x3005}, /* extended */
        {0x302A, 0x302F},
        {0x3031, 0x3035}, /* extended */
        {0x3099, 0x3099},
        {0x309A, 0x309A}, /* combining char */
        {0x309D, 0x309E},
        {0x30FC, 0x30FE} /* extended */
};

/*!
 * \brief The name char table array size.
 */
#define NAMECHARTABLESIZE (sizeof(NameChar) / sizeof(NameChar[0]))

/*!
 * \brief Frees one ElementStack item.
 */
static void Parser_freeElementStackItem(
        /*! [in] The element stack item to free. */
        IXML_ElementStack *pItem)
{
        assert(pItem != NULL);
        if (pItem->element != NULL) {
                free(pItem->element);
                pItem->element = NULL;
        }
        if (pItem->namespaceUri != NULL) {
                free(pItem->namespaceUri);
                pItem->namespaceUri = NULL;
        }
        if (pItem->prefix != NULL) {
                free(pItem->prefix);
                pItem->prefix = NULL;
        }
}

/*!
 * \brief Frees namespaceURI item.
 */
static void Parser_freeNsURI(
        /*! [in] The name space URI item to free. */
        IXML_NamespaceURI *pNsURI)
{
        assert(pNsURI != NULL);
        if (pNsURI->nsURI != NULL) {
                free(pNsURI->nsURI);
        }
        if (pNsURI->prefix != NULL) {
                free(pNsURI->prefix);
        }
}

/*!
 * \brief Frees all temporary memory allocated by xmlparser.
 */
static void Parser_free(
        /*! [in] The XML parser. */
        Parser *xmlParser)
{
        IXML_ElementStack *pElement;
        IXML_ElementStack *pNextElement;
        IXML_NamespaceURI *pNsURI;
        IXML_NamespaceURI *pNextNsURI;

        if (xmlParser == NULL) {
                return;
        }

        if (xmlParser->dataBuffer != NULL) {
                free(xmlParser->dataBuffer);
        }

        ixml_membuf_destroy(&(xmlParser->tokenBuf));
        ixml_membuf_destroy(&(xmlParser->lastElem));

        pElement = xmlParser->pCurElement;
        while (pElement != NULL) {
                Parser_freeElementStackItem(pElement);

                pNsURI = pElement->pNsURI;
                while (pNsURI != NULL) {
                        pNextNsURI = pNsURI->nextNsURI;
                        Parser_freeNsURI(pNsURI);
                        free(pNsURI);
                        pNsURI = pNextNsURI;
                }

                pNextElement = pElement->nextElement;
                free(pElement);
                pElement = pNextElement;
        }

        free(xmlParser);
}

/*!
 * \brief Skips document type declaration
 */
static int Parser_skipDocType(
        /*! [in,out] The pointer to the skipped point. */
        char **pstr)
{
        char *pCur = *pstr;
        /* default there is no nested < */
        char *pNext = NULL;
        int num = 1;

        assert((*pstr) != NULL);
        if (*pstr == NULL) {
                return IXML_FAILED;
        }

        while ((pCur != NULL) && (num != 0) && (*pCur != 0)) {
                if (*pCur == '<') {
                        num++;
                } else if (*pCur == '>') {
                        num--;
                } else if (*pCur == '"') {
                        pNext = strchr(pCur + 1, '"');
                        if (pNext == NULL) {
                                return IXML_SYNTAX_ERR;
                        }

                        pCur = pNext;
                }

                pCur++;
        }

        if (num == 0) {
                *pstr = pCur;
                return IXML_SUCCESS;
        } else {
                return IXML_SYNTAX_ERR;
        }
}

/*!
 * \brief Skips all characters in the string until it finds the skip key.
 * Then it skips the skip key and returns.
 */
static int Parser_skipString(
        /*! [in,out] The pointer to the skipped point. */
        char **pstrSrc,
        /*! [in] The skip key. */
        const char *strSkipKey)
{
        if (!(*pstrSrc) || !strSkipKey) {
                return IXML_FAILED;
        }

        while ((**pstrSrc) &&
                strncmp(*pstrSrc, strSkipKey, strlen(strSkipKey)) != 0) {
                (*pstrSrc)++;
        }

        if (**pstrSrc == '\0') {
                return IXML_SYNTAX_ERR;
        }
        *pstrSrc = *pstrSrc + strlen(strSkipKey);

        return IXML_SUCCESS;
}

/*!
 * \brief Skip white spaces.
 */
static void Parser_skipWhiteSpaces(
        /*! [in] The XML parser. */
        Parser *xmlParser)
{
        while ((*(xmlParser->curPtr) != 0) &&
                (strchr(WHITESPACE, (int)*(xmlParser->curPtr)) != NULL)) {
                xmlParser->curPtr++;
        }
}

/*!
 * \brief Skips XML declarations.
 */
static int Parser_skipXMLDecl(
        /*! [in,out] The XML parser. */
        Parser *xmlParser)
{
        int rc = IXML_FAILED;

        assert(xmlParser);
        if (xmlParser == NULL) {
                return rc;
        }

        rc = Parser_skipString(&(xmlParser->curPtr), END_PI);
        Parser_skipWhiteSpaces(xmlParser);
        return rc;
}

/*!
 * \brief Skips all characters in the string until it finds the skip key.
 * Then it skips the skip key and returns.
 */
static int Parser_skipComment(
        /*! [in,out] The pointer to the skipped point. */
        char **pstrSrc)
{
        char *pStrFound = NULL;

        assert((*pstrSrc) != NULL);
        if (*pstrSrc == NULL) {
                return IXML_FAILED;
        }

        pStrFound = strstr(*pstrSrc, END_COMMENT);
        if ((pStrFound != NULL) && (pStrFound != *pstrSrc) &&
                (*(pStrFound - 1) != '-')) {
                *pstrSrc = pStrFound + strlen(END_COMMENT);
        } else {
                return IXML_SYNTAX_ERR;
        }

        return IXML_SUCCESS;
}

/*!
 * \brief Skip comment, PI and white space.
 */
static int Parser_skipMisc(
        /*! [in] The XML parser. */
        Parser *xmlParser)
{
        int rc = IXML_SUCCESS;
        int done = 0;

        while ((done == 0) && (rc == IXML_SUCCESS)) {
                if (strncasecmp(xmlParser->curPtr,
                            (char *)BEGIN_COMMENT,
                            strlen(BEGIN_COMMENT)) == 0) {
                        /* <!-- */
                        rc = Parser_skipComment(&(xmlParser->curPtr));

                } else if (strncasecmp(xmlParser->curPtr,
                                   (char *)XMLDECL,
                                   strlen(XMLDECL)) == 0 ||
                        strncasecmp(xmlParser->curPtr,
                                (char *)XMLDECL2,
                                strlen(XMLDECL2)) == 0) {
                        /* <?xml or <?xml? */
                        rc = IXML_SYNTAX_ERR;
                } else if (strncasecmp(xmlParser->curPtr,
                                   (char *)BEGIN_PI,
                                   strlen(BEGIN_PI)) == 0) {
                        /* <? */
                        rc = Parser_skipString(&xmlParser->curPtr, END_PI);
                } else {
                        done = 1;
                }
                Parser_skipWhiteSpaces(xmlParser);
        }

        return rc;
}

/*!
 * \brief Skip prolog.
 */
static int Parser_skipProlog(
        /*! [in,out] The XML parser. */
        Parser *xmlParser)
{
        int rc = IXML_SUCCESS;

        assert(xmlParser != NULL);
        if (xmlParser == NULL) {
                return IXML_FAILED;
        }

        Parser_skipWhiteSpaces(xmlParser);

        if (strncmp(xmlParser->curPtr, (char *)XMLDECL, strlen(XMLDECL)) == 0) {
                /* <?xml */
                rc = Parser_skipXMLDecl(xmlParser);
                if (rc != IXML_SUCCESS) {
                        return rc;
                }
        }

        rc = Parser_skipMisc(xmlParser);
        if ((rc == IXML_SUCCESS) &&
                strncmp(xmlParser->curPtr,
                        (char *)BEGIN_DOCTYPE,
                        strlen(BEGIN_DOCTYPE)) == 0) {
                /* <! DOCTYPE */
                xmlParser->curPtr++;
                rc = Parser_skipDocType(&(xmlParser->curPtr));
        }

        if (rc == IXML_SUCCESS) {
                rc = Parser_skipMisc(xmlParser);
        }

        return rc;
}

/*!
 * \brief Set the last element to be the given string.
 */
static int Parser_setLastElem(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The string to copy from. */
        const char *s)
{
        int rc;

        if ((xmlParser == NULL) || (s == NULL)) {
                return IXML_FAILED;
        }

        rc = ixml_membuf_assign_str(&(xmlParser->lastElem), s);
        return rc;
}

/*!
 * \brief Clear token buffer.
 */
static void Parser_clearTokenBuf(
        /*! [in] The XML parser. */
        Parser *xmlParser)
{
        ixml_membuf_destroy(&(xmlParser->tokenBuf));
}

/*!
 * \brief In UTF-8, characters are encoded using sequences of 1 to 6 octets.
 * This functions will return a UTF-8 character value and its octets number.
 *
 * \return The UTF-8 character converted to an int (32 bits).
 */
static int Parser_UTF8ToInt(
        /*! [in] The pointer to the character to encode. */
        const char *ss,
        /*! [out] The number of octets of the UTF-8 encoding of this character.
         */
        ptrdiff_t *len)
{
        const unsigned char *s = (const unsigned char *)ss;
        int c = *s;

        if (c <= 127) {
                /* if c<=127, c is just the character. */
                *len = 1;
                return c;
        } else if ((c & 0xE0) == 0xC0 && (s[1] & 0xc0) == 0x80) {
                /* a sequence of 110xxxxx and 10xxxxxx? */
                *len = 2;
                return ((c & 0x1f) << 6) | (s[1] & 0x3f);
        } else if ((c & 0xF0) == 0xE0 && (s[1] & 0xc0) == 0x80 &&
                (s[2] & 0xc0) == 0x80) {
                /* a sequence of 1110xxxx,10xxxxxx and 10xxxxxx ? */
                *len = 3;
                return ((c & 0x0f) << 12) | ((s[1] & 0x3f) << 6) |
                        (s[2] & 0x3f);
        } else if ((c & 0xf8) == 0xf0 && (s[1] & 0xc0) == 0x80 &&
                (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80) {
                /* a sequence of 11110xxx,10xxxxxx,10xxxxxx and 10xxxxxx ? */
                *len = 4;
                return ((c & 0x07) << 18) | ((s[1] & 0x3f) << 12) |
                        ((s[2] & 0x3f) << 6) | (s[3] & 0x3f);
        } else if ((c & 0xfc) == 0xf8 && (s[1] & 0xc0) == 0x80 &&
                (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80 &&
                (s[4] & 0xc0) == 0x80) {
                /* a sequence of 111110xx,10xxxxxx,10xxxxxx,10xxxxxx,10xxxxxx ?
                 */
                *len = 5;
                return ((c & 0x03) << 24) | ((s[1] & 0x3f) << 18) |
                        ((s[2] & 0x3f) << 12) | ((s[3] & 0x3f) << 6) |
                        (s[4] & 0x3f);
        } else if ((c & 0xfe) == 0xfc && (s[1] & 0xc0) == 0x80 &&
                (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80 &&
                (s[4] & 0xc0) == 0x80 && (s[5] & 0xc0) == 0x80) {
                /* a sequence of 1111110x,10xxxxxx,10xxxxxx,10xxxxxx,10xxxxxx
                 * and 10xxxxxx ? */
                *len = 6;
                return ((c & 0x01) << 30) | ((s[1] & 0x3f) << 24) |
                        ((s[2] & 0x3f) << 18) | ((s[3] & 0x3f) << 12) |
                        ((s[4] & 0x3f) << 6) | (s[5] & 0x3f);
        } else {
                /* none of above, error */
                int ret = 0;
                int line = __LINE__;
                if (g_error_char) {
                        *len = 1;
                        ret = g_error_char;
                } else {
                        *len = 0;
                        ret = -1;
                }
                IxmlPrintf(
                        __FILE__, line, "Parser_UTF8ToInt", "Error %d\n", ret);
                return ret;
        }
}

/*!
 * \brief Will determine whether character c is in the table of tbl (either
 * Letter table or NameChar table).
 *
 * \return 1 or 0.
 */
static int Parser_isCharInTable(
        /*! [in] Character to check. */
        int c,
        /*! [in] Table to use. */
        char_info_t *tbl,
        /*! [in] Size of the table. */
        int sz)
{
        int t = 0;
        int b = sz - 1;
        int m;

        while (t <= b) {
                m = (t + b) / 2;
                if (c < tbl[m].l) {
                        b = m - 1;
                } else if (c > tbl[m].h) {
                        t = m + 1;
                } else {
                        return 1;
                }
        }

        return 0;
}

/*!
 * \brief Check whether c (int) is in LetterTable or NameCharTable.
 */
static int Parser_isNameChar(
        /*! [in] The character to check. */
        int c,
        /*! [in] 1 if you also want to check in the NameChar table. */
        int bNameChar)
{
        if (Parser_isCharInTable(c, Letter, (int)LETTERTABLESIZE)) {
                return 1;
        }

        if (bNameChar &&
                Parser_isCharInTable(c, NameChar, (int)NAMECHARTABLESIZE)) {
                return 1;
        }

        return 0;
}

/*!
 * \brief see XML 1.0 (2nd Edition) 2.2.
 */
static int Parser_isXmlChar(
        /*! [in] The character to check. */
        int c)
{
        return c == 0x9 || c == 0xA || c == 0xD || (c >= 0x20 && c <= 0xD7FF) ||
                (c >= 0xE000 && c <= 0xFFFD) || (c >= 0x10000 && c <= 0x10FFFF);
}

/*!
 * \brief Returns next char value and its length.
 */
static int Parser_getChar(
        /*! [in] . */
        const char *src,
        /*! [in,out] . */
        ptrdiff_t *cLen)
{
        int ret = -1;
        int line = 0;
        const char *pnum;
        int sum;
        char c;
        int i;

        if (src == NULL || cLen == NULL) {
                line = __LINE__;
                ret = -1;
                goto ExitFunction;
        }

        *cLen = 0;
        if (*src != '&') {
                if (*src > 0 && Parser_isXmlChar((int)*src)) {
                        *cLen = 1;
                        ret = *src;
                        goto ExitFunction;
                }

                i = Parser_UTF8ToInt(src, cLen);
                if (!Parser_isXmlChar(i)) {
                        line = __LINE__;
                        ret = g_error_char ? g_error_char : -1;
                        goto ExitFunction;
                }

                line = __LINE__;
                ret = i;
                goto ExitFunction;
        } else if (strncasecmp(src, QUOT, strlen(QUOT)) == 0) {
                *cLen = (int)strlen(QUOT);
                ret = '"';
                goto ExitFunction;
        } else if (strncasecmp(src, LT, strlen(LT)) == 0) {
                *cLen = (int)strlen(LT);
                ret = '<';
                goto ExitFunction;
        } else if (strncasecmp(src, GT, strlen(GT)) == 0) {
                *cLen = (int)strlen(GT);
                ret = '>';
                goto ExitFunction;
        } else if (strncasecmp(src, APOS, strlen(APOS)) == 0) {
                *cLen = (int)strlen(APOS);
                ret = '\'';
                goto ExitFunction;
        } else if (strncasecmp(src, AMP, strlen(AMP)) == 0) {
                *cLen = (int)strlen(AMP);
                ret = '&';
                goto ExitFunction;
        } else if (strncasecmp(src, ESC_HEX, strlen(ESC_HEX)) == 0) {
                /* Read in escape characters of type &#xnn where nn is a
                 * hexadecimal value */
                pnum = src + strlen(ESC_HEX);
                sum = 0;
                while (strchr(HEX_NUMBERS, (int)*pnum) != 0) {
                        c = *pnum;
                        if (c <= '9') {
                                sum = sum * 16 + (c - '0');
                        } else if (c <= 'F') {
                                sum = sum * 16 + (c - 'A' + 10);
                        } else {
                                sum = sum * 16 + (c - 'a' + 10);
                        }
                        pnum++;
                }
                if (pnum == src || *pnum != ';' || !Parser_isXmlChar(sum)) {
                        line = __LINE__;
                        goto fail_entity;
                }
                *cLen = pnum - src + 1;
                ret = sum;
                goto ExitFunction;
        } else if (strncasecmp(src, ESC_DEC, strlen(ESC_DEC)) == 0) {
                /* Read in escape characters of type &#nn where nn is a decimal
                 * value */
                pnum = src + strlen(ESC_DEC);
                sum = 0;
                while (strchr(DEC_NUMBERS, (int)*pnum) != 0) {
                        sum = sum * 10 + (*pnum - '0');
                        pnum++;
                }
                if ((pnum == src) || *pnum != ';' || !Parser_isXmlChar(sum)) {
                        line = __LINE__;
                        goto fail_entity;
                }
                *cLen = pnum - src + 1;
                ret = sum;
                goto ExitFunction;
        }

fail_entity:
        if (g_error_char) {
                *cLen = 1;
                ret = '&';
                goto ExitFunction;
        }
        ret = -1;

ExitFunction:
        if (ret == -1 || (g_error_char && ret == g_error_char)) {
                IxmlPrintf(__FILE__, line, "Parser_getChar", "Error %d\n", ret);
        }

        return ret;
}

/*!
 * \brief Appends c to token buffer.
 */
static int Parser_appendTokBufChar(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The character to append. */
        char c)
{
        int rc;

        rc = ixml_membuf_append(&(xmlParser->tokenBuf), &c);
        return rc;
}

/*!
 * \brief Encodes a character to its UTF-8 character string, and return its
 * length.
 *
 * \return The length of the encoded string in bytes.
 */
static int Parser_intToUTF8(
        /*! [in] The character to encode. */
        int c,
        /*! [out] The resultant UTF-8 encoded string. */
        utf8char s)
{
        if (c < 0)
                return 0;

        if (c <= 127) {
                s[0] = (char)c;
                s[1] = (char)0;
                return 1;
        } else if (c <= 0x07FF) {
                /* 0x0080 < c <= 0x07FF */
                s[0] = (char)(0xC0 | (c >> 6));
                s[1] = (char)(0x80 | (c & 0x3f));
                s[2] = (char)0;
                return 2;
        } else if (c <= 0xFFFF) {
                /* 0x0800 < c <= 0xFFFF */
                s[0] = (char)(0xE0 | (c >> 12));
                s[1] = (char)(0x80 | ((c >> 6) & 0x3f));
                s[2] = (char)(0x80 | (c & 0x3f));
                s[3] = (char)0;
                return 3;
        } else if (c <= 0x1FFFFF) {
                /* 0x10000 < c <= 0x1FFFFF */
                s[0] = (char)(0xF0 | (c >> 18));
                s[1] = (char)(0x80 | ((c >> 12) & 0x3f));
                s[2] = (char)(0x80 | ((c >> 6) & 0x3f));
                s[3] = (char)(0x80 | (c & 0x3f));
                s[4] = (char)0;
                return 4;
        } else if (c <= 0x3FFFFFF) {
                /* 0x200000 < c <= 3FFFFFF */
                s[0] = (char)(0xF8 | (c >> 24));
                s[1] = (char)(0x80 | ((c >> 18) & 0x3f));
                s[2] = (char)(0x80 | ((c >> 12) & 0x3f));
                s[3] = (char)(0x80 | ((c >> 6) & 0x3f));
                s[4] = (char)(0x80 | (c & 0x3f));
                s[5] = (char)0;
                return 5;
        } else if (c <= 0x7FFFFFFF) {
                /* 0x4000000 < c <= 7FFFFFFF */
                s[0] = (char)(0xFC | (c >> 30));
                s[1] = (char)(0x80 | ((c >> 24) & 0x3f));
                s[2] = (char)(0x80 | ((c >> 18) & 0x3f));
                s[3] = (char)(0x80 | ((c >> 12) & 0x3f));
                s[4] = (char)(0x80 | ((c >> 6) & 0x3f));
                s[5] = (char)(0x80 | (c & 0x3f));
                s[6] = (char)0;
                return 6;
        } else {
                /* illegal */
                return 0;
        }
}

/*!
 * \brief Appends string s to token buffer.
 */
static int Parser_appendTokBufStr(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The string to append. */
        const char *s)
{
        int rc = IXML_SUCCESS;

        if (s != NULL) {
                rc = ixml_membuf_append_str(&(xmlParser->tokenBuf), s);
        }

        return rc;
}

/*!
 * \brief Copy string in src into xml parser token buffer
 */
static int Parser_copyToken(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The string to copy from. */
        const char *src,
        /*! [in] The lenght to copy. */
        ptrdiff_t len)
{
        int ret = IXML_SUCCESS;
        int line = 0;
        int i;
        int c;
        ptrdiff_t cl;
        const char *psrc;
        const char *pend;
        utf8char uch;

        if (!src || len <= 0) {
                line = __LINE__;
                ret = IXML_FAILED;
                goto ExitFunction;
        }

        psrc = src;
        pend = src + len;

        while (psrc < pend) {
                c = Parser_getChar(psrc, &cl);
                if (c <= 0) {
                        line = __LINE__;
                        ret = IXML_FAILED;
                        goto ExitFunction;
                }

                if (cl == 1) {
                        Parser_appendTokBufChar(xmlParser, (char)c);
                        psrc++;
                } else {
                        i = Parser_intToUTF8(c, uch);
                        if (i == 0) {
                                line = __LINE__;
                                ret = IXML_FAILED;
                                goto ExitFunction;
                        }
                        Parser_appendTokBufStr(xmlParser, uch);
                        psrc += cl;
                }
        }

        if (psrc > pend) {
                line = __LINE__;
                ret = IXML_FAILED;
                goto ExitFunction;
        }

ExitFunction:
        if (ret != IXML_SUCCESS) {
                IxmlPrintf(
                        __FILE__, line, "Parser_copyToken", "Error %d\n", ret);
        }

        return ret;
}

/*!
 * \brief Return the length of next token in tokenBuff.
 */
static ptrdiff_t Parser_getNextToken(
        /*! [in] The XML parser. */
        Parser *xmlParser)
{
        ptrdiff_t tokenLength = 0;
        int temp;
        ptrdiff_t tlen;
        int rc;

        Parser_clearTokenBuf(xmlParser);

        if (*(xmlParser->curPtr) == '\0') {
                return 0;
        }
        /* skip XML instructions */
        rc = Parser_skipMisc(xmlParser);
        if (rc != IXML_SUCCESS) {
                return 0;
        }
        /* Attribute value logic must come first, since all text untokenized
         * until end-quote */
        if (*(xmlParser->curPtr) == QUOTE) {
                tokenLength = 1;
        } else if (*(xmlParser->curPtr) == SINGLEQUOTE) {
                tokenLength = 1;
        } else if (*(xmlParser->curPtr) == LESSTHAN) {
                /* Check for start tags */
                temp = Parser_UTF8ToInt(xmlParser->curPtr + 1, &tlen);
                if (temp == '/') {
                        /* token is '</' end tag */
                        tokenLength = 2;
                } else if (Parser_isNameChar(temp, 0)) {
                        /* '<' found, so return '<' token */
                        tokenLength = 1;
                } else {
                        /* error */
                        return 0;
                }
        } else if (*(xmlParser->curPtr) == EQUALS) {
                /* Check for '=' token, return it as a token */
                tokenLength = 1;
        } else if (*(xmlParser->curPtr) == SLASH) {
                if (*(xmlParser->curPtr + 1) == GREATERTHAN) {
                        /* token '/>' found */
                        tokenLength = 2;
                        /* fix */
                        xmlParser->savePtr = xmlParser->curPtr;
                }
        } else if (*(xmlParser->curPtr) == GREATERTHAN) {
                /* > found, so return it as a token */
                tokenLength = 1;
        } else if (Parser_isNameChar(
                           Parser_UTF8ToInt(xmlParser->curPtr, &tlen), 0)) {
                /* Check for name tokens, name found, so find out how long it is
                 */
                ptrdiff_t iIndex = tlen;

                while (Parser_isNameChar(
                        Parser_UTF8ToInt(xmlParser->curPtr + iIndex, &tlen),
                        1)) {
                        iIndex += tlen;
                }
                tokenLength = iIndex;
        } else {
                return 0;
        }

        /* Copy the token to the return string */
        if (Parser_copyToken(xmlParser, xmlParser->curPtr, tokenLength) !=
                IXML_SUCCESS) {
                return 0;
        }

        xmlParser->curPtr += tokenLength;
        return tokenLength;
}

/*!
 * \brief Version of strdup() that handles NULL input.
 *
 * \return The same as strdup().
 */
static char *safe_strdup(
        /*! [in] String to be duplicated. */
        const char *s)
{
        assert(s != NULL);

        if (s == NULL) {
                return strdup((const char *)"");
        }
        return strdup(s);
}

/*!
 * \brief Processes the STag as defined by XML spec.
 */
static int Parser_processSTag(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The Node to process. */
        IXML_Node *node)
{
        char *pCurToken = NULL;
        int rc;

        if (Parser_getNextToken(xmlParser) == 0) {
                return IXML_SYNTAX_ERR;
        }

        pCurToken = (xmlParser->tokenBuf).buf;
        if (pCurToken != NULL) {
                node->nodeName = safe_strdup(pCurToken);
                if (node->nodeName == NULL) {
                        return IXML_INSUFFICIENT_MEMORY;
                }
        } else {
                return IXML_SYNTAX_ERR;
        }

        rc = Parser_setLastElem(xmlParser, node->nodeName);
        if (rc != IXML_SUCCESS) {
                /* no need to free node->nodeName, main loop will free it */
                return IXML_FAILED;
        }

        rc = Parser_setNodePrefixAndLocalName(node);
        if (rc != IXML_SUCCESS) {
                /* no need to free node->nodeName, main loop will free it */
                return IXML_FAILED;
        }

        node->nodeValue = NULL;
        node->nodeType = eELEMENT_NODE;

        xmlParser->savePtr = xmlParser->curPtr;
        if (Parser_getNextToken(xmlParser) == 0) {
                /* no need to free node->nodeName, main loop will free it */
                return IXML_SYNTAX_ERR;
        }

        pCurToken = (xmlParser->tokenBuf).buf;
        /* check to see what is the next token */
        if (strcmp(pCurToken, "/>") == 0) {
                /* empty element */
                xmlParser->state = eELEMENT;
                /* backup to /> */
                xmlParser->curPtr = xmlParser->savePtr;
        } else if (strcmp(pCurToken, ">") == 0) {
                /* expecting text node */
                xmlParser->state = eCONTENT;
        } else {
                xmlParser->state = eATTRIBUTE;
                xmlParser->curPtr = xmlParser->savePtr;
        }

        return IXML_SUCCESS;
}

/*!
 * \brief
 */
static int Parser_skipPI(
        /*! [in,out] The pointer to the skipped point. */
        char **pSrc)
{
        char *pEnd = NULL;

        assert(*pSrc);
        if (*pSrc == NULL) {
                return IXML_FAILED;
        }

        if ((strncasecmp(*pSrc, (char *)XMLDECL, strlen(XMLDECL)) == 0) ||
                (strncasecmp(*pSrc, (char *)XMLDECL2, strlen(XMLDECL2)) == 0)) {
                /* not allowed */
                return IXML_SYNTAX_ERR;
        }

        if (strncasecmp(*pSrc, (char *)BEGIN_PI, strlen(BEGIN_PI)) == 0) {
                pEnd = strstr(*pSrc, END_PI);
                if ((pEnd != NULL) && (pEnd != *pSrc)) {
                        *pSrc = pEnd + strlen(BEGIN_PI);
                } else {
                        return IXML_SYNTAX_ERR;
                }
        }

        return IXML_SUCCESS;
}

/*!
 * \brief Processes CDSection as defined by XML spec.
 *
 * \return
 */
static int Parser_processCDSect(
        /*! [in] . */
        char **pSrc,
        /*! [in] The Node to process. */
        IXML_Node *node)
{
        char *pEnd;
        size_t tokenLength = (size_t)0;
        char *pCDataStart;

        if (*pSrc == NULL) {
                return IXML_FAILED;
        }

        pCDataStart = *pSrc + strlen(CDSTART);
        pEnd = pCDataStart;
        while ((Parser_isXmlChar((int)*pEnd)) && (*pEnd != '\0')) {
                if (strncmp(pEnd, CDEND, strlen(CDEND)) == 0) {
                        break;
                } else {
                        pEnd++;
                }
        }

        if ((pEnd - pCDataStart > 0) && (*pEnd != '\0')) {
                tokenLength = (size_t)pEnd - (size_t)pCDataStart;
                node->nodeValue = (char *)malloc(tokenLength + (size_t)1);
                if (node->nodeValue == NULL) {
                        return IXML_INSUFFICIENT_MEMORY;
                }
                strncpy(node->nodeValue, pCDataStart, tokenLength);
                node->nodeValue[tokenLength] = '\0';

                node->nodeName = safe_strdup(CDATANODENAME);
                if (node->nodeName == NULL) {
                        /* no need to free node->nodeValue at all, bacause node
                         * contents will be freed by the main loop. */
                        return IXML_INSUFFICIENT_MEMORY;
                }

                node->nodeType = eCDATA_SECTION_NODE;
                *pSrc = pEnd + strlen(CDEND);
                return IXML_SUCCESS;
        } else {
                return IXML_SYNTAX_ERR;
        }
}

/*!
 * \brief Processes the CONTENT as defined in XML spec.
 */
static int Parser_processContent(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The Node to process. */
        IXML_Node *node)
{
        int ret = IXML_SUCCESS;
        int line = 0;
        char *pEndContent;
        ptrdiff_t tokenLength;
        const char *notAllowed = "]]>";
        char *pCurToken = NULL;

        /* save pointer for backup */
        xmlParser->savePtr = xmlParser->curPtr;
        Parser_skipWhiteSpaces(xmlParser);

        if (*(xmlParser->curPtr) == '\0') {
                /* end of file is reached */
                ret = IXML_SUCCESS;
                goto ExitFunction;
        }

        pEndContent = xmlParser->curPtr;
        if (*pEndContent == LESSTHAN) {
                if (strncmp(pEndContent, (char *)CDSTART, strlen(CDSTART)) ==
                        0) {
                        if (Parser_processCDSect(&pEndContent, node) !=
                                IXML_SUCCESS) {
                                line = __LINE__;
                                ret = IXML_SYNTAX_ERR;
                                goto ExitFunction;
                        } else {
                                xmlParser->curPtr = pEndContent;
                        }
                } else if (strncmp(pEndContent,
                                   (char *)BEGIN_COMMENT,
                                   strlen(BEGIN_COMMENT)) == 0) {
                        if (Parser_skipComment(&pEndContent) != IXML_SUCCESS) {
                                line = __LINE__;
                                ret = IXML_SYNTAX_ERR;
                                goto ExitFunction;
                        } else {
                                xmlParser->curPtr = pEndContent;
                        }
                } else if (strncmp(pEndContent,
                                   (char *)BEGIN_PI,
                                   strlen(BEGIN_PI)) == 0) {
                        if (Parser_skipPI(&pEndContent) != IXML_SUCCESS) {
                                line = __LINE__;
                                ret = IXML_SYNTAX_ERR;
                                goto ExitFunction;
                        } else {
                                xmlParser->curPtr = pEndContent;
                        }
                } else {
                        /* empty content */
                        xmlParser->state = eELEMENT;
                }
        } else {
                /* backup */
                xmlParser->curPtr = xmlParser->savePtr;
                pEndContent = xmlParser->curPtr;

                while ((*pEndContent != LESSTHAN) &&
                        (strncmp(pEndContent,
                                 (const char *)notAllowed,
                                 strlen(notAllowed)) != 0) &&
                        *pEndContent) {
                        pEndContent++;
                }

                if (strncmp(pEndContent,
                            (const char *)notAllowed,
                            strlen(notAllowed)) == 0) {
                        line = __LINE__;
                        ret = IXML_SYNTAX_ERR;
                        goto ExitFunction;
                }

                tokenLength = pEndContent - xmlParser->curPtr;
                Parser_clearTokenBuf(xmlParser);

                if (Parser_copyToken(xmlParser,
                            xmlParser->curPtr,
                            tokenLength) != IXML_SUCCESS) {
                        line = __LINE__;
                        ret = IXML_SYNTAX_ERR;
                        goto ExitFunction;
                }

                pCurToken = (xmlParser->tokenBuf).buf;
                if (pCurToken != NULL) {
                        node->nodeValue = safe_strdup(pCurToken);
                        if (node->nodeValue == NULL) {
                                line = __LINE__;
                                ret = IXML_INSUFFICIENT_MEMORY;
                                goto ExitFunction;
                        }
                } else {
                        line = __LINE__;
                        ret = IXML_SYNTAX_ERR;
                        goto ExitFunction;
                }

                node->nodeName = safe_strdup(TEXTNODENAME);
                if (node->nodeName == NULL) {
                        line = __LINE__;
                        ret = IXML_SYNTAX_ERR;
                        goto ExitFunction;
                }
                node->nodeType = eTEXT_NODE;

                /* adjust curPtr */
                xmlParser->curPtr += tokenLength;
        }

ExitFunction:
        if (ret != IXML_SUCCESS) {
                IxmlPrintf(__FILE__,
                        line,
                        "Parser_processContent",
                        "Error %d\n",
                        ret);
        }

        return ret;
}

/*!
 * \brief Process ETag as defined by XML spec.
 */
static int Parser_processETag(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The Node to process. */
        IXML_Node *node,
        /*! [out] . */
        int *bETag)
{
        int ret = IXML_SUCCESS;
        int line = 0;
        char *pCurToken = NULL;

        assert(xmlParser != NULL);
        if (Parser_getNextToken(xmlParser) == 0) {
                line = __LINE__;
                ret = IXML_SYNTAX_ERR;
                goto ExitFunction;
        }

        pCurToken = (xmlParser->tokenBuf).buf;
        if (pCurToken == NULL) {
                line = __LINE__;
                ret = IXML_SYNTAX_ERR;
                goto ExitFunction;
        }
        node->nodeName = safe_strdup(pCurToken);
        if (node->nodeName == NULL) {
                line = __LINE__;
                ret = IXML_INSUFFICIENT_MEMORY;
                goto ExitFunction;
        }

        node->nodeValue = NULL;
        node->nodeType = eELEMENT_NODE;

        Parser_skipWhiteSpaces(xmlParser);

        /* read the >  */
        if (Parser_getNextToken(xmlParser) == 0) {
                line = __LINE__;
                ret = IXML_SYNTAX_ERR;
                goto ExitFunction;
        }

        pCurToken = (xmlParser->tokenBuf).buf;
        if (pCurToken == NULL) {
                /* no need to free node->nodeName, it is freed by main loop */
                line = __LINE__;
                ret = IXML_SYNTAX_ERR;
                goto ExitFunction;
        }

        if (strcmp(pCurToken, ">") != 0) {
                line = __LINE__;
                ret = IXML_SYNTAX_ERR;
                goto ExitFunction;
        }

        *bETag = 1;

ExitFunction:
        if (ret != IXML_SUCCESS) {
                IxmlPrintf(__FILE__,
                        line,
                        "Parser_processETag",
                        "Error %d\n",
                        ret);
        }

        return ret;
}

/*!
 * \brief Unimplemented function.
 *
 * \return IXML_SUCCESS.
 */
#if 0
static int Parser_parseReference(
	/*! [in] Currently unused. */
	char *pStr)
{
	/* place holder for future implementation */
	return IXML_SUCCESS;
	pStr = pStr;
}
#endif

/*!
 * \brief Return the namespce as defined as prefix.
 */
static char *Parser_getNameSpace(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The prefix. */
        const char *prefix)
{
        IXML_ElementStack *pCur;
        IXML_NamespaceURI *pNsUri;

        pCur = xmlParser->pCurElement;
        if (strcmp(pCur->prefix, prefix) != 0) {
                pNsUri = pCur->pNsURI;
                while (pNsUri != NULL) {
                        if (strcmp(pNsUri->prefix, prefix) == 0) {
                                return pNsUri->nsURI;
                        }
                        pNsUri = pNsUri->nextNsURI;
                }
        } else {
                return pCur->namespaceUri;
        }

        return NULL;
}

/*!
 * \brief Add a namespace definition.
 */
static int Parser_addNamespace(
        /*! [in] The XML parser. */
        Parser *xmlParser)
{
        IXML_Node *pNode;
        IXML_ElementStack *pCur;
        const char *namespaceUri;

        pNode = xmlParser->pNeedPrefixNode;
        pCur = xmlParser->pCurElement;
        if (!pNode->prefix) {
                /* element does not have prefix */
                if (strcmp(pNode->nodeName, pCur->element) != 0)
                        return IXML_FAILED;
                if (pCur->namespaceUri) {
                        /* it would be wrong that pNode->namespace != NULL. */
                        assert(pNode->namespaceURI == NULL);
                        pNode->namespaceURI = safe_strdup(pCur->namespaceUri);
                        if (!pNode->namespaceURI)
                                return IXML_INSUFFICIENT_MEMORY;
                }
                xmlParser->pNeedPrefixNode = NULL;
        } else {
                if (!pCur->prefix ||
                        ((strcmp(pNode->nodeName, pCur->element) != 0) &&
                                (strcmp(pNode->prefix, pCur->prefix) != 0)))
                        return IXML_FAILED;
                namespaceUri = Parser_getNameSpace(xmlParser, pCur->prefix);
                if (namespaceUri) {
                        pNode->namespaceURI = safe_strdup(namespaceUri);
                        if (!pNode->namespaceURI)
                                return IXML_INSUFFICIENT_MEMORY;
                        xmlParser->pNeedPrefixNode = NULL;
                }
        }

        return IXML_SUCCESS;
}

/*!
 * \brief Add namespace definition.
 */
static int Parser_xmlNamespace(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The Node to process. */
        IXML_Node *newNode)
{
        IXML_ElementStack *pCur = xmlParser->pCurElement;
        IXML_NamespaceURI *pNewNs = NULL;
        IXML_NamespaceURI *pNs = NULL;
        IXML_NamespaceURI *pPrevNs = NULL;
        int ret = IXML_SUCCESS;
        int line = 0;

        /* if the newNode contains a namespace definition */
        assert(newNode->nodeName != NULL);

        if (strcmp(newNode->nodeName, "xmlns") == 0) {
                /* default namespace def. */
                if (pCur->namespaceUri != NULL) {
                        free(pCur->namespaceUri);
                }
                pCur->namespaceUri = safe_strdup(newNode->nodeValue);
                if (pCur->namespaceUri == NULL) {
                        ret = IXML_INSUFFICIENT_MEMORY;
                        line = __LINE__;
                        goto ExitFunction;
                }
        } else if (strncmp(newNode->nodeName, "xmlns:", strlen("xmlns:")) ==
                0) {
                /* namespace definition */
                ret = Parser_setNodePrefixAndLocalName(newNode);
                if (ret != IXML_SUCCESS) {
                        line = __LINE__;
                        goto ExitFunction;
                }

                assert(newNode->localName != NULL);

                if (pCur == NULL) {
                        ret = IXML_FAILED;
                        line = __LINE__;
                        goto ExitFunction;
                }
                if (pCur->prefix != NULL &&
                        strcmp(pCur->prefix, newNode->localName) == 0) {
                        if (pCur->namespaceUri != NULL) {
                                free(pCur->namespaceUri);
                        }
                        pCur->namespaceUri = safe_strdup(newNode->nodeValue);
                        if (pCur->namespaceUri == NULL) {
                                ret = IXML_INSUFFICIENT_MEMORY;
                                line = __LINE__;
                                goto ExitFunction;
                        }
                } else {
                        pPrevNs = pCur->pNsURI;
                        pNs = pPrevNs;
                        while (pNs != NULL) {
                                if (pNs->prefix != NULL &&
                                        strcmp(pNs->prefix,
                                                newNode->localName) == 0) {
                                        /* replace namespace definition */
                                        break;
                                } else {
                                        pPrevNs = pNs;
                                        pNs = pNs->nextNsURI;
                                }
                        }
                        if (pNs == NULL) {
                                /* a new definition */
                                pNewNs = (IXML_NamespaceURI *)malloc(
                                        sizeof(IXML_NamespaceURI));
                                if (pNewNs == NULL) {
                                        ret = IXML_INSUFFICIENT_MEMORY;
                                        line = __LINE__;
                                        goto ExitFunction;
                                }
                                memset(pNewNs, 0, sizeof(IXML_NamespaceURI));
                                pNewNs->prefix =
                                        safe_strdup(newNode->localName);
                                if (pNewNs->prefix == NULL) {
                                        free(pNewNs);
                                        ret = IXML_INSUFFICIENT_MEMORY;
                                        line = __LINE__;
                                        goto ExitFunction;
                                }
                                pNewNs->nsURI = safe_strdup(newNode->nodeValue);
                                if (pNewNs->nsURI == NULL) {
                                        Parser_freeNsURI(pNewNs);
                                        free(pNewNs);
                                        ret = IXML_INSUFFICIENT_MEMORY;
                                        line = __LINE__;
                                        goto ExitFunction;
                                }
                                if (pCur->pNsURI == NULL) {
                                        pCur->pNsURI = pNewNs;
                                } else {
                                        pPrevNs->nextNsURI = pNewNs;
                                }
                        } else {
                                /* udpate the namespace */
                                if (pNs->nsURI != NULL) {
                                        free(pNs->nsURI);
                                }
                                pNs->nsURI = safe_strdup(newNode->nodeValue);
                                if (pNs->nsURI == NULL) {
                                        ret = IXML_INSUFFICIENT_MEMORY;
                                        line = __LINE__;
                                        goto ExitFunction;
                                }
                        }
                }
        }
        if (xmlParser->pNeedPrefixNode != NULL) {
                ret = Parser_addNamespace(xmlParser);
                line = __LINE__;
                goto ExitFunction;
        }

ExitFunction:
        if (ret != IXML_SUCCESS && ret != IXML_FILE_DONE) {
                IxmlPrintf(__FILE__,
                        line,
                        "Parser_xmlNamespace",
                        "Error %d\n",
                        ret);
        }

        return ret;
}

/*!
 * \brief Processes attribute.
 *
 * \return IXML_SUCCESS or failure code.
 */
static int Parser_processAttribute(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The Node to process. */
        IXML_Node *node)
{
        int ret = IXML_SUCCESS;
        int line = 0;
        ptrdiff_t tlen = 0;
        char *strEndQuote = NULL;
        char *pCur = NULL;
        char *pCurToken = NULL;

        assert(xmlParser);

        if (xmlParser == NULL) {
                ret = IXML_FAILED;
                line = __LINE__;
                goto ExitFunction;
        }
        pCurToken = xmlParser->tokenBuf.buf;
        if (pCurToken == NULL) {
                ret = IXML_SYNTAX_ERR;
                line = __LINE__;
                goto ExitFunction;
        }
        if (Parser_isNameChar(Parser_UTF8ToInt(pCurToken, &tlen), 0) == 0) {
                ret = IXML_SYNTAX_ERR;
                line = __LINE__;
                goto ExitFunction;
        }
        /* copy in the attribute name */
        node->nodeName = safe_strdup(pCurToken);
        if (node->nodeName == NULL) {
                ret = IXML_INSUFFICIENT_MEMORY;
                line = __LINE__;
                goto ExitFunction;
        }
        /* read in the "=" sign */
        if (Parser_getNextToken(xmlParser) == 0) {
                ret = IXML_SYNTAX_ERR;
                line = __LINE__;
                goto ExitFunction;
        }

        pCurToken = xmlParser->tokenBuf.buf;
        if (*pCurToken != EQUALS) {
                ret = IXML_SYNTAX_ERR;
                line = __LINE__;
                goto ExitFunction;
        }
        /* read in the single quote or double quote */
        if (Parser_getNextToken(xmlParser) == 0) {
                ret = IXML_SYNTAX_ERR;
                line = __LINE__;
                goto ExitFunction;
        }
        /* pCurToken is either quote or single quote */
        pCurToken = (xmlParser->tokenBuf).buf;
        if (*pCurToken != QUOTE && *pCurToken != SINGLEQUOTE) {
                ret = IXML_SYNTAX_ERR;
                line = __LINE__;
                goto ExitFunction;
        }
        strEndQuote = strstr(xmlParser->curPtr, pCurToken);
        if (strEndQuote == NULL) {
                ret = IXML_SYNTAX_ERR;
                line = __LINE__;
                goto ExitFunction;
        }
        /* check between curPtr and strEndQuote,
         * whether there are illegal chars. */
        pCur = xmlParser->curPtr;
        while (pCur < strEndQuote) {
                if (*pCur == '<') {
                        ret = IXML_SYNTAX_ERR;
                        line = __LINE__;
                        goto ExitFunction;
                }
                /*if (*pCur == '&') {
                        Parser_parseReference(++pCur);
                }*/
                pCur++;
        }
        /* clear token buffer */
        Parser_clearTokenBuf(xmlParser);
        if (strEndQuote != xmlParser->curPtr) {
                ret = Parser_copyToken(xmlParser,
                        xmlParser->curPtr,
                        strEndQuote - xmlParser->curPtr);
                if (ret != IXML_SUCCESS) {
                        ret = IXML_SYNTAX_ERR;
                        line = __LINE__;
                        goto ExitFunction;
                }
        }
        /* skip the ending quote */
        xmlParser->curPtr = strEndQuote + 1;
        pCurToken = xmlParser->tokenBuf.buf;
        if (pCurToken != NULL) {
                /* attribute has value, like a="c" */
                node->nodeValue = safe_strdup(pCurToken);
                if (node->nodeValue == NULL) {
                        ret = IXML_INSUFFICIENT_MEMORY;
                        line = __LINE__;
                        goto ExitFunction;
                }
        } else {
                /* if attribute doesn't have value, like a=""
                 * somewhere on other places is this copied */
                node->nodeValue = malloc(sizeof(char));
                *(node->nodeValue) = '\0';
        }
        node->nodeType = eATTRIBUTE_NODE;

        /* check whether this is a new namespace definition */
        ret = Parser_xmlNamespace(xmlParser, node);
        if (ret != IXML_SUCCESS) {
                line = __LINE__;
                goto ExitFunction;
        }
        /* read ahead to see whether we have more attributes */
        xmlParser->savePtr = xmlParser->curPtr;
        if (Parser_getNextToken(xmlParser) == 0) {
                ret = IXML_SYNTAX_ERR;
                line = __LINE__;
                goto ExitFunction;
        }

        pCurToken = xmlParser->tokenBuf.buf;
        if (strcmp(pCurToken, "<") == 0) {
                ret = IXML_FAILED;
                line = __LINE__;
                goto ExitFunction;
        } else if (strcmp(pCurToken, ">") != 0) {
                /* more attribute? */
                /* backup */
                xmlParser->curPtr = xmlParser->savePtr;
        } else {
                xmlParser->state = eCONTENT;
        }

ExitFunction:
        if (ret != IXML_SUCCESS && ret != IXML_FILE_DONE) {
                IxmlPrintf(__FILE__,
                        line,
                        "Parser_processAttribute",
                        "Error %d\n",
                        ret);
        }

        return ret;
}

/*!
 * \brief Get the next node.
 *
 * \return IXML_SUCCESS and the next node or IXML_FILE_DONE or an error.
 */
static int Parser_getNextNode(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [out] The XML parser. */
        IXML_Node *node,
        /*! [out] The XML parser. */
        int *bETag)
{
        char *pCurToken = NULL;
        char *lastElement = NULL;
        int ret = IXML_SUCCESS;
        int line = 0;
        ptrdiff_t tokenLen = 0;

        /* endof file reached? */
        if (*(xmlParser->curPtr) == '\0') {
                *bETag = 1;
                line = __LINE__;
                ret = IXML_FILE_DONE;
                goto ExitFunction;
        }

        switch (xmlParser->state) {
        case eCONTENT:
                line = __LINE__;
                ret = Parser_processContent(xmlParser, node);
                goto ExitFunction;
        default:
                Parser_skipWhiteSpaces(xmlParser);
                tokenLen = Parser_getNextToken(xmlParser);
                if (tokenLen == 0 && xmlParser->pCurElement == NULL &&
                        *(xmlParser->curPtr) == '\0') {
                        /* comments after the xml doc */
                        line = __LINE__;
                        ret = IXML_SUCCESS;
                        goto ExitFunction;
                } else if ((xmlParser->tokenBuf).length == (size_t)0) {
                        line = __LINE__;
                        ret = IXML_SYNTAX_ERR;
                        goto ExitFunction;
                }

                pCurToken = (xmlParser->tokenBuf).buf;
                if (*pCurToken == GREATERTHAN) {
                        line = __LINE__;
                        ret = IXML_SUCCESS;
                        goto ExitFunction;
                } else if (strcmp(pCurToken, ENDTAG) == 0) {
                        /* we got </, read next element */
                        line = __LINE__;
                        ret = Parser_processETag(xmlParser, node, bETag);
                        goto ExitFunction;
                } else if (*pCurToken == LESSTHAN) {
                        line = __LINE__;
                        ret = Parser_processSTag(xmlParser, node);
                        goto ExitFunction;
                } else if (strcmp(pCurToken, COMPLETETAG) == 0) {
                        lastElement = (xmlParser->lastElem).buf;
                        if (lastElement == NULL) {
                                line = __LINE__;
                                ret = IXML_SYNTAX_ERR;
                                goto ExitFunction;
                        }

                        node->nodeName = safe_strdup(lastElement);
                        if (node->nodeName == NULL) {
                                line = __LINE__;
                                ret = IXML_INSUFFICIENT_MEMORY;
                                goto ExitFunction;
                        }
                        node->nodeType = eELEMENT_NODE;
                        *bETag = 1;

                        line = __LINE__;
                        ret = IXML_SUCCESS;
                        goto ExitFunction;
                } else if (xmlParser->pCurElement != NULL) {
                        switch (xmlParser->state) {
                        case eATTRIBUTE:
                                if (Parser_processAttribute(xmlParser, node) !=
                                        IXML_SUCCESS) {
                                        line = __LINE__;
                                        ret = IXML_SYNTAX_ERR;
                                        goto ExitFunction;
                                }
                                break;
                        default:
                                line = __LINE__;
                                ret = IXML_SYNTAX_ERR;
                                goto ExitFunction;
                        }
                } else {
                        line = __LINE__;
                        ret = IXML_SYNTAX_ERR;
                        goto ExitFunction;
                }
        }

ExitFunction:
        if (ret != IXML_SUCCESS && ret != IXML_FILE_DONE) {
                IxmlPrintf(__FILE__,
                        line,
                        "Parser_getNextNode",
                        "Error %d\n",
                        ret);
        }

        return ret;
}

/*!
 * \brief Decides whether element's prefix is already defined.
 */
static int Parser_ElementPrefixDefined(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The Node to process. */
        IXML_Node *newNode,
        /*! [in,out] The name space URI. */
        char **nsURI)
{
        IXML_ElementStack *pCur = xmlParser->pCurElement;
        IXML_NamespaceURI *pNsUri;

        while (pCur != NULL) {
                if ((pCur->prefix != NULL) &&
                        (strcmp(pCur->prefix, newNode->prefix) == 0)) {
                        *nsURI = pCur->namespaceUri;
                        return 1;
                } else {
                        pNsUri = pCur->pNsURI;

                        while (pNsUri != NULL) {
                                if (strcmp(pNsUri->prefix, newNode->prefix) ==
                                        0) {
                                        *nsURI = pNsUri->nsURI;
                                        return 1;
                                } else {
                                        pNsUri = pNsUri->nextNsURI;
                                }
                        }
                }

                pCur = pCur->nextElement;
        }

        return 0;
}

/*!
 * \brief Set element's namespace.
 */
static int Parser_setElementNamespace(
        /*! [in] The Element Node to process. */
        IXML_Element *newElement,
        /*! [in] The name space string. */
        const char *nsURI)
{
        if (newElement != NULL) {
                if (newElement->n.namespaceURI != NULL) {
                        return IXML_SYNTAX_ERR;
                } else {
                        (newElement->n).namespaceURI = safe_strdup(nsURI);
                        if ((newElement->n).namespaceURI == NULL) {
                                return IXML_INSUFFICIENT_MEMORY;
                        }
                }
        }

        return IXML_SUCCESS;
}

/*!
 * \brief Reports whether the new attribute is the same as an existing one.
 *
 * \return 1 if the new attribute is the same as an existing one.
 */
static int isDuplicateAttribute(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The node attribute to compare. */
        IXML_Node *newAttrNode)
{
        IXML_Node *elementNode = NULL;
        IXML_Node *attrNode = NULL;

        elementNode = xmlParser->currentNodePtr;
        attrNode = elementNode->firstAttr;
        while (attrNode != NULL) {
                if (strcmp(attrNode->nodeName, newAttrNode->nodeName) == 0) {
                        return 1;
                }

                attrNode = attrNode->nextSibling;
        }

        return 0;
}

/*!
 * \brief Processes the attribute name.
 *
 * \return IXML_SUCCESS if successful, otherwise or an error code.
 */
static int Parser_processAttributeName(
        /*! [in] The XML document. */
        IXML_Document *rootDoc,
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The Node to process. */
        IXML_Node *newNode)
{
        IXML_Attr *attr = NULL;
        int rc = IXML_SUCCESS;

        if (isDuplicateAttribute(xmlParser, newNode)) {
                return IXML_SYNTAX_ERR;
        }

        rc = ixmlDocument_createAttributeEx(rootDoc, newNode->nodeName, &attr);
        if (rc != IXML_SUCCESS) {
                return rc;
        }

        rc = ixmlNode_setNodeProperties((IXML_Node *)attr, newNode);
        if (rc != IXML_SUCCESS) {
                ixmlAttr_free(attr);
                return rc;
        }

        rc = ixmlElement_setAttributeNode(
                (IXML_Element *)xmlParser->currentNodePtr, attr, NULL);
        if (rc != IXML_SUCCESS) {
                ixmlAttr_free(attr);
        }
        return rc;
}

/*!
 * \brief Push a new element onto element stack.
 *
 * \return
 */
static int Parser_pushElement(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The element node to push. */
        IXML_Node *newElement)
{
        IXML_ElementStack *pCurElement = NULL;
        IXML_ElementStack *pNewStackElement = NULL;

        assert(newElement);
        if (newElement != NULL) {
                /* push new element */
                pNewStackElement =
                        (IXML_ElementStack *)malloc(sizeof(IXML_ElementStack));
                if (pNewStackElement == NULL) {
                        return IXML_INSUFFICIENT_MEMORY;
                }

                memset(pNewStackElement, 0, sizeof(IXML_ElementStack));
                /* the element member includes both prefix and name */

                pNewStackElement->element = safe_strdup(newElement->nodeName);
                if (pNewStackElement->element == NULL) {
                        free(pNewStackElement);
                        return IXML_INSUFFICIENT_MEMORY;
                }

                if (newElement->prefix != 0) {
                        pNewStackElement->prefix =
                                safe_strdup(newElement->prefix);
                        if (pNewStackElement->prefix == NULL) {
                                Parser_freeElementStackItem(pNewStackElement);
                                free(pNewStackElement);
                                return IXML_INSUFFICIENT_MEMORY;
                        }
                }

                if (newElement->namespaceURI != 0) {
                        pNewStackElement->namespaceUri =
                                safe_strdup(newElement->namespaceURI);
                        if (pNewStackElement->namespaceUri == NULL) {
                                Parser_freeElementStackItem(pNewStackElement);
                                free(pNewStackElement);
                                return IXML_INSUFFICIENT_MEMORY;
                        }
                }

                pCurElement = xmlParser->pCurElement;

                /* insert the new element into the top of the stack */
                pNewStackElement->nextElement = pCurElement;
                xmlParser->pCurElement = pNewStackElement;
        }

        return IXML_SUCCESS;
}

/*!
 * \brief Reports whether there is a top level element in the parser.
 *
 * \return 1 if there is a top level element in the parser.
 */
static int isTopLevelElement(
        /*! [in] The XML parser. */
        Parser *xmlParser)
{
        assert(xmlParser);
        return xmlParser->pCurElement == NULL;
}

/*!
 * \brief Decide whether the current element has default namespace
 */
static int Parser_hasDefaultNamespace(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in,out] The name space URI. */
        char **nsURI)
{
        IXML_ElementStack *pCur = xmlParser->pCurElement;

        while (pCur != NULL) {
                if ((pCur->prefix == NULL) && (pCur->namespaceUri != NULL)) {
                        *nsURI = pCur->namespaceUri;
                        return 1;
                } else {
                        pCur = pCur->nextElement;
                }
        }

        return 0;
}

/*!
 * \brief Processes element name.
 *
 * \return IXML_SUCCESS if successful, otherwise or an error code.
 */
static int Parser_processElementName(
        /*! [in] The XML document. */
        IXML_Document *rootDoc,
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The Node to process. */
        IXML_Node *newNode)
{
        IXML_Element *newElement = NULL;
        char *nsURI = NULL;
        int rc = IXML_SUCCESS;

        if (xmlParser->bHasTopLevel) {
                if (isTopLevelElement(xmlParser)) {
                        return IXML_SYNTAX_ERR;
                }
        } else {
                xmlParser->bHasTopLevel = 1;
        }

        xmlParser->savePtr = xmlParser->curPtr;
        rc = ixmlDocument_createElementEx(
                rootDoc, newNode->nodeName, &newElement);
        if (rc != IXML_SUCCESS) {
                return rc;
        }

        rc = ixmlNode_setNodeProperties((IXML_Node *)newElement, newNode);
        if (rc != IXML_SUCCESS) {
                ixmlElement_free(newElement);
                return rc;
        }

        if (newNode->prefix) {
                /* element has namespace prefix */
                if (!Parser_ElementPrefixDefined(xmlParser, newNode, &nsURI)) {
                        /* read next node to see whether it includes namespace
                         * definition */
                        xmlParser->pNeedPrefixNode = (IXML_Node *)newElement;
                } else {
                        /* fill in the namespace */
                        Parser_setElementNamespace(newElement, nsURI);
                }
        } else {
                /* does element has default namespace */
                /* the node may have default namespace definition */
                if (Parser_hasDefaultNamespace(xmlParser, &nsURI)) {
                        Parser_setElementNamespace(newElement, nsURI);
                } else {
                        switch (xmlParser->state) {
                        case eATTRIBUTE:
                                /* the default namespace maybe defined later */
                                xmlParser->pNeedPrefixNode =
                                        (IXML_Node *)newElement;
                                break;
                        default:
                                break;
                        }
                }
        }

        rc = ixmlNode_appendChild(
                xmlParser->currentNodePtr, (IXML_Node *)newElement);
        if (rc != IXML_SUCCESS) {
                ixmlElement_free(newElement);
                return rc;
        }

        xmlParser->currentNodePtr = (IXML_Node *)newElement;

        /* push element to stack */
        rc = Parser_pushElement(xmlParser, (IXML_Node *)newElement);
        return rc;
}

/*!
 * \brief Check if a new node->nodeName matches top of element stack.
 *
 * \return 1 if matches.
 */
static int Parser_isValidEndElement(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The node. */
        IXML_Node *newNode)
{
        assert(xmlParser);

        if (xmlParser->pCurElement == NULL) {
                return 0;
        }

        assert(xmlParser->pCurElement->element);
        assert(newNode);
        assert(newNode->nodeName);
        return strcmp(xmlParser->pCurElement->element, newNode->nodeName) == 0;
}

/*!
 * \brief Remove element from element stack.
 */
static void Parser_popElement(
        /*! [in] The XML parser. */
        Parser *xmlParser)
{
        IXML_ElementStack *pCur = NULL;
        IXML_NamespaceURI *pnsUri = NULL;
        IXML_NamespaceURI *pNextNS = NULL;

        pCur = xmlParser->pCurElement;
        if (pCur != NULL) {
                xmlParser->pCurElement = pCur->nextElement;
                Parser_freeElementStackItem(pCur);
                pnsUri = pCur->pNsURI;
                while (pnsUri != NULL) {
                        pNextNS = pnsUri->nextNsURI;
                        Parser_freeNsURI(pnsUri);
                        free(pnsUri);
                        pnsUri = pNextNS;
                }
                free(pCur);
        }
}

/*!
 * \brief Verifies endof element tag is the same as the openning element tag.
 */
static int Parser_eTagVerification(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The Node to process. */
        IXML_Node *newNode)
{
        assert(newNode->nodeName);
        assert(xmlParser->currentNodePtr);

        switch (newNode->nodeType) {
        case eELEMENT_NODE:
                if (Parser_isValidEndElement(xmlParser, newNode)) {
                        Parser_popElement(xmlParser);
                } else {
                        /* syntax error */
                        return IXML_SYNTAX_ERR;
                }
                break;
        default:
                break;
        }

        if (strcmp(newNode->nodeName, xmlParser->currentNodePtr->nodeName) ==
                0) {
                xmlParser->currentNodePtr =
                        xmlParser->currentNodePtr->parentNode;
        } else {
                return IXML_SYNTAX_ERR;
        }

        return IXML_SUCCESS;
}

/*!
 * \brief Parses the xml file and returns the DOM document tree.
 *
 * \return
 */
static int Parser_parseDocument(
        /*! [out] The XML document. */
        IXML_Document **retDoc,
        /*! [in] The XML parser. */
        Parser *xmlParser)
{
        IXML_Document *gRootDoc = NULL;
        IXML_Node newNode;
        int bETag = 0;
        IXML_Node *tempNode = NULL;
        int rc = IXML_SUCCESS;
        IXML_CDATASection *cdataSecNode = NULL;

        /* It is important that the node gets initialized here, otherwise things
         * can go wrong on the error handler. */
        ixmlNode_init(&newNode);

        rc = ixmlDocument_createDocumentEx(&gRootDoc);
        if (rc != IXML_SUCCESS) {
                goto ErrorHandler;
        }

        xmlParser->currentNodePtr = (IXML_Node *)gRootDoc;

        rc = Parser_skipProlog(xmlParser);
        if (rc != IXML_SUCCESS) {
                goto ErrorHandler;
        }

        while (bETag == 0) {
                /* clear the newNode contents. Redundant on the first iteration,
                 * but nonetheless, necessary due to the possible calls to
                 * ErrorHandler above. Currently, this is just a memset to zero.
                 */
                ixmlNode_init(&newNode);

                if (Parser_getNextNode(xmlParser, &newNode, &bETag) ==
                        IXML_SUCCESS) {
                        if (bETag == 0) {
                                switch (newNode.nodeType) {
                                case eELEMENT_NODE:
                                        rc = Parser_processElementName(
                                                gRootDoc, xmlParser, &newNode);
                                        if (rc != IXML_SUCCESS) {
                                                goto ErrorHandler;
                                        }
                                        break;

                                case eTEXT_NODE:
                                        rc = ixmlDocument_createTextNodeEx(
                                                gRootDoc,
                                                newNode.nodeValue,
                                                &tempNode);
                                        if (rc != IXML_SUCCESS) {
                                                goto ErrorHandler;
                                        }

                                        rc = ixmlNode_appendChild(
                                                xmlParser->currentNodePtr,
                                                tempNode);
                                        if (rc != IXML_SUCCESS) {
                                                goto ErrorHandler;
                                        }

                                        break;

                                case eCDATA_SECTION_NODE:
                                        rc = ixmlDocument_createCDATASectionEx(
                                                gRootDoc,
                                                newNode.nodeValue,
                                                &cdataSecNode);
                                        if (rc != IXML_SUCCESS) {
                                                goto ErrorHandler;
                                        }

                                        rc = ixmlNode_appendChild(
                                                xmlParser->currentNodePtr,
                                                &(cdataSecNode->n));
                                        if (rc != IXML_SUCCESS) {
                                                goto ErrorHandler;
                                        }
                                        break;

                                case eATTRIBUTE_NODE:
                                        rc = Parser_processAttributeName(
                                                gRootDoc, xmlParser, &newNode);
                                        if (rc != IXML_SUCCESS) {
                                                goto ErrorHandler;
                                        }
                                        break;

                                default:
                                        break;
                                }
                        } else {
                                /* ETag==1, endof element tag. */
                                rc = Parser_eTagVerification(
                                        xmlParser, &newNode);
                                if (rc != IXML_SUCCESS) {
                                        goto ErrorHandler;
                                }
                                xmlParser->state = eCONTENT;
                        }

                        /* reset bETag flag */
                        bETag = 0;

                } else if (bETag) {
                        /* file is done */
                        break;
                } else {
                        rc = IXML_FAILED;
                        goto ErrorHandler;
                }
                Parser_freeNodeContent(&newNode);
        }

        if (xmlParser->pCurElement != NULL) {
                rc = IXML_SYNTAX_ERR;
                goto ErrorHandler;
        }

        *retDoc = (IXML_Document *)gRootDoc;
        Parser_free(xmlParser);
        return rc;

ErrorHandler:
        Parser_freeNodeContent(&newNode);
        ixmlDocument_free(gRootDoc);
        Parser_free(xmlParser);
        return rc;
}

int Parser_isValidXmlName(const DOMString name)
{
        const char *pstr = NULL;
        size_t i = (size_t)0;
        size_t nameLen = (size_t)0;

        assert(name != NULL);

        nameLen = strlen(name);
        pstr = name;
        if (Parser_isNameChar((int)*pstr, 0)) {
                for (i = (size_t)1; i < nameLen; ++i) {
                        if (Parser_isNameChar((int)*(pstr + i), 1) == 0) {
                                /* illegal char */
                                return 0;
                        }
                }
        }

        return 1;
}

void Parser_setErrorChar(char c) { g_error_char = c; }

#ifdef IXML_HAVE_SCRIPTSUPPORT
void Parser_setBeforeFree(IXML_BeforeFreeNode_t hndlr)
{
        Before_Free_callback = hndlr;
}

IXML_BeforeFreeNode_t Parser_getBeforeFree() { return Before_Free_callback; }
#endif

/*!
 * \brief Initializes a xml parser.
 *
 * \return The parser object or \b NULL if there is not enough memory.
 */
static Parser *Parser_init()
{
        Parser *newParser = NULL;

        newParser = (Parser *)malloc(sizeof(Parser));
        if (newParser == NULL) {
                return NULL;
        }

        memset(newParser, 0, sizeof(Parser));
        ixml_membuf_init(&(newParser->tokenBuf));
        ixml_membuf_init(&(newParser->lastElem));

        return newParser;
}

/*!
 * \brief Read a xml file or buffer contents into xml parser.
 */
static int Parser_readFileOrBuffer(
        /*! [in] The XML parser. */
        Parser *xmlParser,
        /*! [in] The file name or the buffer to copy, according to the
         * parameter "file". */
        const char *xmlFileName,
        /*! [in] 1 if you want to read from a file, 0 if xmlFileName is
         * the buffer to copy to the parser. */
        int file)
{
        long fileSize = 0;
        size_t bytesRead = (size_t)0;
        FILE *xmlFilePtr = NULL;

        if (file) {
                xmlFilePtr = fopen(xmlFileName, "rb");
                if (xmlFilePtr == NULL) {
                        return IXML_NO_SUCH_FILE;
                } else {
                        fseek(xmlFilePtr, 0, SEEK_END);
                        fileSize = ftell(xmlFilePtr);
                        if (fileSize <= 0) {
                                fclose(xmlFilePtr);
                                return IXML_SYNTAX_ERR;
                        }

                        xmlParser->dataBuffer =
                                (char *)malloc((size_t)fileSize + (size_t)1);
                        if (xmlParser->dataBuffer == NULL) {
                                fclose(xmlFilePtr);
                                return IXML_INSUFFICIENT_MEMORY;
                        }

                        fseek(xmlFilePtr, 0, SEEK_SET);
                        bytesRead = fread(xmlParser->dataBuffer,
                                (size_t)1,
                                (size_t)fileSize,
                                xmlFilePtr);
                        /* append null */
                        xmlParser->dataBuffer[bytesRead] = '\0';
                        fclose(xmlFilePtr);
                }
        } else {
                xmlParser->dataBuffer = safe_strdup(xmlFileName);
                if (xmlParser->dataBuffer == NULL) {
                        return IXML_INSUFFICIENT_MEMORY;
                }
        }

        return IXML_SUCCESS;
}

/*!
 * \brief Parses a xml file and return the DOM tree.
 */
int Parser_LoadDocument(
        /*! [out] The output document tree. */
        IXML_Document **retDoc,
        /*! [in] The file name or the buffer to copy, according to the
         * parameter "file". */
        const char *xmlFileName,
        /*! [in] 1 if you want to read from a file, 0 if xmlFileName is
         * the buffer to copy to the parser. */
        int file)
{
        int rc = IXML_SUCCESS;
        Parser *xmlParser = NULL;

        xmlParser = Parser_init();
        if (xmlParser == NULL) {
                return IXML_INSUFFICIENT_MEMORY;
        }

        rc = Parser_readFileOrBuffer(xmlParser, xmlFileName, file);
        if (rc != IXML_SUCCESS) {
                Parser_free(xmlParser);
                return rc;
        }

        xmlParser->curPtr = xmlParser->dataBuffer;
        rc = Parser_parseDocument(retDoc, xmlParser);
        return rc;
}

void Parser_freeNodeContent(IXML_Node *nodeptr)
{
        if (nodeptr == NULL) {
                return;
        }

        if (nodeptr->nodeName != NULL) {
                free(nodeptr->nodeName);
        }

        if (nodeptr->nodeValue != NULL) {
                free(nodeptr->nodeValue);
        }

        if (nodeptr->namespaceURI != NULL) {
                free(nodeptr->namespaceURI);
        }

        if (nodeptr->prefix != NULL) {
                free(nodeptr->prefix);
        }

        if (nodeptr->localName != NULL) {
                free(nodeptr->localName);
        }
}

/*!
 * \brief Set the node prefix and localName as defined by the nodeName in the
 * form of ns:name.
 */
int Parser_setNodePrefixAndLocalName(
        /*! [in,out] The Node to process. */
        IXML_Node *node)
{
        char *pStrPrefix = NULL;
        char *pLocalName;
        ptrdiff_t nPrefix;

        assert(node != NULL);
        if (node == NULL) {
                return IXML_FAILED;
        }

        pStrPrefix = strchr(node->nodeName, ':');
        if (pStrPrefix == NULL) {
                node->prefix = NULL;
                node->localName = safe_strdup(node->nodeName);
                if (node->localName == NULL) {
                        return IXML_INSUFFICIENT_MEMORY;
                }

        } else {
                /* fill in the local name and prefix */
                pLocalName = (char *)pStrPrefix + 1;
                nPrefix = pStrPrefix - node->nodeName;
                node->prefix = malloc((size_t)nPrefix + (size_t)1);
                if (!node->prefix) {
                        return IXML_INSUFFICIENT_MEMORY;
                }

                memset(node->prefix, 0, (size_t)nPrefix + (size_t)1);
                strncpy(node->prefix, node->nodeName, (size_t)nPrefix);

                node->localName = safe_strdup(pLocalName);
                if (node->localName == NULL) {
                        free(node->prefix);
                        /* no need to free really, main loop will frees it
                         * when return code is not success */
                        node->prefix = NULL;
                        return IXML_INSUFFICIENT_MEMORY;
                }
        }

        return IXML_SUCCESS;
}
